package com.maybach.core.security;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.audi.dubbo.api.admin.models.AdminModel;
import com.maybach.util.AssertUtil;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.ExecutionException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * Created by houenxun on 16/1/22.
 */
public class AdminUser   implements Subject , IAdminUser,Serializable {
    private static final long serialVersionUID = 1L;
    private Subject subject;
    private transient AdminModel adminModel;

    @Override
    public String getName() {
        String name = this.getRealName();
        if(StringUtils.isNotEmpty(name)){
            return name;
        }else{
            name = this.getNickName();
            if(StringUtils.isNotEmpty(name)){
                return name;
            }else{
                name = this.getLoginName();
            }
        }
        return name;
    }

    public static final String ADMIN_MODEL_KEY = "maybach_admin_model_key";


    public AdminUser(Subject subject) {
        AssertUtil.notNull(subject ,"subject");
        this.subject = subject;
    }

    private AdminModel getAdminModel(){
        if(null != adminModel){
            return adminModel;
        }
        synchronized (this){
            if(null != adminModel){
                return adminModel;
            }
            if(this.isAuthenticated()){
                adminModel = (AdminModel)this.getSession().getAttribute(ADMIN_MODEL_KEY);
            }
        }

        return adminModel;
    }

    @Override
    public String getPrincipal() {
        return (String)subject.getPrincipal();
    }

    @Override
    public PrincipalCollection getPrincipals() {
        return subject.getPrincipals();
    }

    @Override
    public boolean isPermitted(String permission) {
        return subject.isPermitted(permission);
    }

    @Override
    public boolean isPermitted(Permission permission) {
        return subject.isPermitted(permission);
    }

    @Override
    public boolean[] isPermitted(String... permissions) {
        return subject.isPermitted(permissions);
    }

    @Override
    public boolean[] isPermitted(List<Permission> permissions) {
        return subject.isPermitted(permissions);
    }

    @Override
    public boolean isPermittedAll(String... permissions) {
        return subject.isPermittedAll(permissions);
    }

    @Override
    public boolean isPermittedAll(Collection<Permission> permissions) {
        return subject.isPermittedAll(permissions);
    }

    @Override
    public void checkPermission(String permission) throws AuthorizationException {
        subject.checkPermission(permission);
    }

    @Override
    public void checkPermission(Permission permission) throws AuthorizationException {
        subject.checkPermission(permission);
    }

    @Override
    public void checkPermissions(String... permissions) throws AuthorizationException {
        subject.checkPermissions(permissions);
    }

    @Override
    public void checkPermissions(Collection<Permission> permissions) throws AuthorizationException {
        subject.checkPermissions(permissions);
    }

    @Override
    public boolean hasRole(String roleIdentifier) {
        return subject.hasRole(roleIdentifier);
    }

    @Override
    public boolean[] hasRoles(List<String> roleIdentifiers) {
        return subject.hasRoles(roleIdentifiers);
    }

    @Override
    public boolean hasAllRoles(Collection<String> roleIdentifiers) {
        return subject.hasAllRoles(roleIdentifiers);
    }

    @Override
    public void checkRole(String roleIdentifier) throws AuthorizationException {
        subject.checkRole(roleIdentifier);
    }

    @Override
    public void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException {
        subject.checkRoles(roleIdentifiers);
    }

    @Override
    public void checkRoles(String... roleIdentifiers) throws AuthorizationException {
        subject.checkRoles(roleIdentifiers);
    }

    @Override
    public void login(AuthenticationToken token) throws AuthenticationException {
        subject.login(token);
    }

    @Override
    public boolean isAuthenticated() {
        return subject.isAuthenticated();
    }

    @Override
    public boolean isRemembered() {
        return subject.isRemembered();
    }

    @Override
    public Session getSession() {
        return subject.getSession();
    }

    @Override
    public Session getSession(boolean create) {
        return subject.getSession(create);
    }

    @Override
    public void logout() {
        subject.logout();
    }

    @Override
    public <V> V execute(Callable<V> callable) throws ExecutionException {
        return subject.execute(callable);
    }

    @Override
    public void execute(Runnable runnable) {
        subject.execute(runnable);
    }

    @Override
    public <V> Callable<V> associateWith(Callable<V> callable) {
        return subject.associateWith(callable);
    }

    @Override
    public Runnable associateWith(Runnable runnable) {
        return subject.associateWith(runnable);
    }

    @Override
    public void runAs(PrincipalCollection principals) throws NullPointerException, IllegalStateException {
        subject.runAs(principals);
    }

    @Override
    public boolean isRunAs() {
        return subject.isRunAs();
    }

    @Override
    public PrincipalCollection getPreviousPrincipals() {
        return subject.getPreviousPrincipals();
    }

    @Override
    public PrincipalCollection releaseRunAs() {
        return subject.releaseRunAs();
    }

    @Override
    public void login(String name, String password) {
        this.login(new UsernamePasswordToken(name, password));
    }

    @Override
    public Long getAdminId() {
        AdminModel model = this.getAdminModel();
        if(null != model){
            return model.getAdminId();
        }
        return null;
    }

    @Override
    public String getLoginName() {
        AdminModel model = this.getAdminModel();
        if(null != model){
            return model.getNick();
        }
        return null;
    }

    @Override
    public String getRealName() {
        AdminModel model = this.getAdminModel();
        if(null != model){
            return model.getExtattr();
        }
        return null;
    }

    @Override
    public String getNickName() {
        AdminModel model = this.getAdminModel();
        if(null != model){
            return model.getNick();
        }
        return null;
    }

    @Override
    public String getDepartId() {
        AdminModel model = this.getAdminModel();
        if(null != model){
            return model.getDepartId();
        }
        return null;
    }

    @Override
    public String getDepartmentName() {
        AdminModel model = this.getAdminModel();
        if(null != model){
            return model.getDepartmentName();
        }
        return null;
    }

    @Override
    public List<String> getRoles() {
        List<String> roles = new ArrayList<String>();

        AdminModel model = this.getAdminModel();
        if(null != model){
            roles.addAll(model.getRoleMap().keySet());
        }
        return roles;
    }

    @Override
    public List<String> getauths() {
        List<String> auths = new ArrayList<String>();
        AdminModel model = this.getAdminModel();
        if(null != model){
            auths.addAll(model.getAuthMap().keySet());
        }
        return auths;
    }

    @Override
    public String toString(){
        return ReflectionToStringBuilder.toString(this, ToStringStyle.DEFAULT_STYLE);
    }
}
